import {
  forwardRef,
  useEffect,
  useImperativeHandle,
  Ref,
  useState,
  useRef,
  useCallback,
  useMemo,
} from 'react';
import { connect, useForm } from '@formily/react';
import { CloseOutlined } from '@ant-design/icons';
import { getMessage, TextWidget } from '@inbiz/react';
import { Tag as AntTag, message, Popconfirm } from 'antd';
import { useEvents } from '@inbiz/utils';
import { useModelList } from '@inbiz/hooks';
import { inbiz } from '@inbiz/core';
import { request } from '@inbiz/utils';
import {
  RenderModal,
  IModalRef,
  IModalEmit,
  IModalCallBackEvents,
} from '@inbiz/render';
import { AuthButton, hasAuth } from '@inbiz/basic/AuthForm';
import { defaultProps } from '../../designer/schema';
import api from './api';
import './index.less';

const version = InbizConfig.API_VERSION;
type IProps = {
  className?: string;
  modelname?: string;
  viewMode?:string;
  callBackEvents?: {
    onParamFormat?: <T>(param: T) => Promise<T>;
    onRequest?: (param: any) => Promise<any>;
    onData?: <T>(data: T) => T;
    onBeforeOperationAsync?: (type: 'add' | 'edit' | 'delete', data: object) => Promise<boolean>;
  } & IModalCallBackEvents;
  emit?: {
    (type: 'onload'): void;
    (type: 'onSuccess', arg: any): void;
    (type: 'onError', arg: any): void;
    (type: 'onDelete', arg: any): void;
    (type: 'onAdd', arg: any): void;
    (type: 'onOpen'): void;
    (
      type: 'onClick',
      clickType: 'closeConfirm' | 'closeCancel' | 'closeIcon' | undefined,
      data: object,
    ): void;
    (type: 'onClick', clickType: 'add'): void;
    (type: 'onClick', clickType: 'edit'): void;
    (type: 'onClick', clickType: 'look'): void;
  } & IModalEmit;
  inbiz: inbiz;
  color?: string;
  fontColor?: string;
  sourceModel?: string;
  readOnly?: boolean;
  onChange: (v: string) => void;
  modelkey?: string;
} & typeof defaultProps;

// const useFormilyRef = <T>(current:T):{current:T}=>useMemo(()=>markRaw({current}),[])
type IRef = Ref<ReturnType<typeof api>>;

const Tag = forwardRef((props: IProps, ref: IRef) => {
  const { callBackEvents, emit, color, fontColor, border, radius,viewMode } = props;
  const [configEvents] = useEvents(callBackEvents, emit);
  const { runAsync } = useModelList(configEvents);
  const modalRef = useRef<IModalRef>();

  const [list, $list] = useState<{ id: string }[]>([]);
  const [isLoadData, $isLoadData] = useState<boolean>(false);
  const [visibleState, $visibleState] = useState({}); // 控制删除气泡的显示隐藏

  const [modelTitle, $modelTitle] = useState('');

  const mounting = useRef(true);

  useEffect(() => {
    const clickHandle = () => {
      $visibleState({});
    };
    document.body.addEventListener('click', clickHandle);
    return () => {
      document.body.removeEventListener('click', clickHandle);
    };
  }, []);

  const getList = (bc?: Function) => {
    const paramData = {
      appId: props.inbiz.appInfo.appId,
      key: props.sourceModel!,
      pageInfo: {
        index: 1,
        size: 999,
      },
    };
    runAsync(paramData)
      .then((res) => {
        $list(res?.Rows || []);
        if (mounting.current) {
          emit?.('onload');
          emit?.('onSuccess', res?.Rows);
          mounting.current = false;
        }
        bc && bc();
      })
      .catch((e) => {
        emit?.('onError', e);
      });
  };
  const form = useForm();

  // 获取数据
  useEffect(() => {
    if (props.sourceModel && props?.inbiz?.appInfo || configEvents.current.onRequest) {
      getList();
    }
  }, [props.sourceModel, props?.inbiz?.appInfo, props.showField]);

  useImperativeHandle(
    ref,
    () => ({
      ...api(configEvents, { setState: $list, list, $isLoadData }),
    }),
    [list],
  );

  const modalEmit = useCallback(
    ((type, ...arg) => {
      if (type === 'onAdd' || type === 'onEdit') {
        const paramData = {
          appId: props.inbiz.appInfo.appId,
          key: props.sourceModel!,
          pageInfo: {
            index: 1,
            size: 999,
          },
        };
        // 保存或新增后更新list
        runAsync(paramData)
          .then((res) => {
            $list(res?.Rows || []);
            emit?.('onSuccess', res?.Rows);
          })
          .catch((e) => {
            emit?.('onError', e);
          });
      }
      //@ts-ignore
      emit?.(type, ...arg);
    }) as IModalEmit,
    [],
  );
  // 获取配置操作类型对应的相关操作名称
  const getOprationName = (type: 'delete' | 'add' | 'edit' | 'read') => {
    return props?.operation.table[
      (props?.operation.table || []).findIndex((t) => t.operationType === type)
    ]?.operationName;
  };
  // 是否添加
  const isAdd = (operation: IProps['operation']) => {
    if (props.readOnly) {
      return false;
    }
    return (operation.table || []).findIndex((t) => t.operationType === 'add') !== -1;
  };

  // 是否删除
  const isDelete = (operation: IProps['operation']) => {
    if (props.readOnly) {
      return false;
    }
    const authFlag = hasAuth(
      { table: operation.table, auth: operation.auth },
      'delete',
      props.inbiz?.auth,
    ).auth;
    return (
      (operation.table || []).findIndex((t) => t.operationType === 'delete') !== -1 && authFlag
    );
  };

  // 是否编辑
  const isEdit = (operation: IProps['operation']) => {
    if (props.readOnly) {
      return false;
    }
    const authFlag = hasAuth(
      { table: operation.table, auth: operation.auth },
      'edit',
      props.inbiz?.auth,
    ).auth;
    return (operation.table || []).findIndex((t) => t.operationType === 'edit') !== -1 && authFlag;
  };

  // 是否查看
  const isRead = (operation: IProps['operation']) => {
    if (props.readOnly) {
      return false;
    }
    const authFlag = hasAuth(
      { table: operation.table, auth: operation.auth },
      'read',
      props.inbiz?.auth,
    ).auth;
    return (operation.table || []).findIndex((t) => t.operationType === 'read') !== -1 && authFlag;
  };

  // 添加配置
  const [pageName, pageId] = useMemo(() => {
    const operation = (props.operation.table || []).find((t) => t.operationType === 'add');
    return operation && operation.link ? operation.link.split(',') : [];
  }, [props.operation]);

  // 查看配置
  const [readPageName, readPageId] = useMemo(() => {
    const operation = (props.operation.table || []).find((t) => t.operationType === 'read');
    return operation && operation.link ? operation.link.split(',') : [];
  }, [props.operation]);

  // 编辑配置
  const [editPageName, editPageId] = useMemo(() => {
    const operation = (props.operation.table || []).find((t) => t.operationType === 'edit');
    return operation && operation.link ? operation.link.split(',') : [];
  }, [props.operation]);

  // 删除
  const handleDelete = async (data: { id: string }) => {
    // 删除确定时不调用回调事件，点击图标x的时候触发
    // const runnext = (await configEvents.current.onBeforeOperationAsync?.('delete', data)) ?? true;
    // if (runnext && props.modelname) {
    if (props.modelname) {
      request
        .post(`/inbiz/api/services/modelengine/v${version}/business/data`, {
          data: {
            relation: {
              //@ts-ignore
              name: props.modelname,
              children: null,
            },
            data: {
              //@ts-ignore
              [props.modelname]: [{ id: data.id, _opt: 'del' }],
            },
          },
        })
        .then((res) => {
          if (res && (res.result === 0 || res.result === undefined )) { // result存在时就校验
            emit?.('onDelete', data);
            getList();
            message.success(getMessage('Tag.tips.deleteSucceed'));
          } else {
            const msg = getMessage('global.' + res.message.replace(':', ''));
            if (msg.indexOf('global.') != 0) {
              message.error(msg)
            } else {
              message.error(res.message)
            }
          }
        })
        .catch(() => {
          getList();
        });
    }
  };

  const handleClick = useCallback(
    async (data) => {
      if (!pageId) {
        message.warning(getMessage('Tag.tips.noPage'));
        return;
      }
      const result = (await configEvents.current.onBeforeOperationAsync?.('add', data)) ?? true;
      if (result) {
        modalRef.current?.onOpen({
          data: { ...data },
          queryData: { id: data.id },
          pageId: pageName,
          id: pageName,
        });
      }
    },
    [pageId],
  );

  const handleEditClick = useCallback(
    async (data) => {
      if (!editPageId) {
        message.warning(getMessage('Tag.tips.noPage'));
        return;
      }
      const queryData: Record<string, any> = { id: data.id };
      const field = props.operation?.table.find(item => item.operationType === 'edit')?.field;
      if (field) {
        queryData[field] = data[field]
      }
      const result = (await configEvents.current.onBeforeOperationAsync?.('edit', data)) ?? true;
      if (result) {
        modalRef.current?.onOpen({
          data: { ...data },
          queryData,
          pageId: editPageName,
          id: editPageName,
        });
      }
    },
    [editPageId, props.operation?.table],
  );

  // 查看
  const handleRead = useCallback(
    async (data) => {
      if (!readPageId) {
        message.warning(getMessage('Tag.tips.noPage'));
        return;
      }
      const queryData: Record<string, any> = { id: data.id,_viewMode:'look' };
      const field = props.operation?.table.find(item => item.operationType === 'read')?.field;
      if (field) {
        queryData[field] = data[field]
      }
      const result = (await configEvents.current.onBeforeOperationAsync?.('read', data)) ?? true;
      if (result) {
        modalRef.current?.onOpen({
          data: { ...data },
          queryData,
          pageId: readPageName,
          id: readPageName,
        });
      }
    },
    [readPageId, props.operation?.table],
  );

  const modalWidth = useMemo(() => {
    const {
      width: { widowWidth = 60, widthSuffix = '%' },
    } = props.operation.formItems;
    return widthSuffix === '%' ? `${widowWidth}${widthSuffix}` : widowWidth;
  }, [props.operation]);

  const modalHeight = useMemo(() => {
    const {
      height: { windowHeight = 60, heightSuffix = '%' },
    } = props.operation.formItems;
    return heightSuffix === '%' ? `${windowHeight}${heightSuffix}` : windowHeight;
  }, [props.operation]);
  return (
    <div className="t-tag">
      {list.map((item) => {
        return <>
          {viewMode=='look'? 
          <AntTag
          key={item.id}
          style={{
            border: `${border}px solid #f5f5f5`,
            borderRadius: radius,
          }}
          color={color || 'var(--inbiz-color-primary)'}
        >
          <span
            style={{
              cursor:
                (isRead(props.operation) || isEdit(props.operation)) &&
                  !props.inbiz.browser.designer
                  ? 'pointer'
                  : 'default',
              color: fontColor,
              fontSize: 'var(--inbiz-font-size-base)',
              minWidth: 10,
              minHeight: 10,
            }} 
          >
            {props.showField ? item[props.showField] : '--'}
          </span>
        </AntTag>:
        <AntTag
        closable={
          !props.inbiz.browser.designer
            ? isDelete(props.operation) || isEdit(props.operation)
            : false
        }
        onClick={(e) => {
          document.body.click();
          e.stopPropagation();
          emit?.('onClick', undefined, item);
        }}
        closeIcon={
          <span>
            {isDelete(props.operation) && (
              <Popconfirm
                title={getMessage('Tag.tips.isRemoveTag')}
                overlayClassName="t-tag-popover"
                onConfirm={() => {
                  if (!isLoadData) {
                    emit?.('onClick', 'closeConfirm', item);
                    handleDelete(item);
                  } else {
                    $list((oldData) => {
                      return oldData.filter((item1: object) => {
                        return item1[Object.keys(item1)[0]] !== item[Object.keys(item)[0]];
                      });
                    });
                    emit?.('onDelete', item);
                    message.success(getMessage('Tag.tips.deleteSucceed'));
                  }
                }}
                onCancel={(e: any) => {
                  e.stopPropagation();
                  emit?.('onClick', 'closeCancel', item);
                  $visibleState(() => ({
                    [item.id]: false,
                  }));
                }}
                visible={visibleState[item.id] ? true : false}
                okText={getMessage('Tag.btn.ok')}
                cancelText={getMessage('Tag.btn.cancel')}
              // okButtonProps={{ style: { borderRadius: '8px' } }}
              // cancelButtonProps={{ style: { borderRadius: '8px' } }}
              >
                <div
                  onClick={async (e) => {
                    document.body.click();
                    emit?.('onClick', 'closeIcon', item);
                    e.stopPropagation();
                    const allKeys = Object.keys(visibleState);
                    if (!allKeys.some((item1) => item1 == item.id)) {
                      const runnext =
                        (await configEvents.current.onBeforeOperationAsync?.('delete', item)) ??
                        true;
                      $visibleState(() => ({
                        [item.id]: runnext,
                      }));
                    }
                  }}
                >
                  <CloseOutlined style={{ color: fontColor || '#fff' }} />
                </div>
              </Popconfirm>
            )}
          </span>
        }
        key={item.id}
        style={{
          border: `${border}px solid #f5f5f5`,
          borderRadius: radius,
        }}
        color={color || 'var(--inbiz-color-primary)'}
      >
        <span
          style={{
            cursor:
              (isRead(props.operation) || isEdit(props.operation)) &&
                !props.inbiz.browser.designer
                ? 'pointer'
                : 'default',
            color: fontColor,
            fontSize: 'var(--inbiz-font-size-base)',
            minWidth: 10,
            minHeight: 10,
          }}
          onClick={(e) => {
            e.stopPropagation();
            isEdit(props.operation)
              ? emit?.('onClick', 'edit', item)
              : isRead(props.operation)
                ? emit?.('onClick', 'look', item)
                : emit?.('onClick', undefined, item);
            $visibleState({});
            if (isEdit(props.operation)) {
              $modelTitle(getMessage(getOprationName('edit')));
              setTimeout(() => {
                !props.inbiz.browser.designer && handleEditClick(item);
              }, 0);

              return;
            }
            if (isRead(props.operation)) {
              $modelTitle(getMessage(getOprationName('read')));
              setTimeout(() => {
                !props.inbiz.browser.designer ? handleRead(item) : '';
              }, 0);
            }
          }}
        >
          {props.showField ? item[props.showField] : '--'}
        </span>
      </AntTag>}
      </>
      })}
      {isAdd(props.operation) && !props.inbiz.browser.designer &&viewMode!='look'&& (
        <AuthButton
          auth={props.operation.auth}
          operation={props.operation.table}
          type="add"
          authList={props.inbiz?.auth}
        >
          <div
            className="add-wrap"
            onClick={(e) => {
              e.stopPropagation();
              emit?.('onClick', 'add');
              $modelTitle(getMessage(getOprationName('add')));
              setTimeout(() => {
                handleClick({});
              }, 0);
            }}
          >
            <div className="add">+</div>
            <div className="label">
              <TextWidget>{getOprationName('add')}</TextWidget>
            </div>
          </div>
        </AuthButton>
      )}

      <RenderModal
        title={modelTitle}
        ref={modalRef}
        inbiz={props.inbiz}
        callBackEvents={configEvents}
        emit={modalEmit}
        readonly={modelTitle === getMessage(getOprationName('read'))}
        maskClosable={false}
        keyboard={false}
        style={{ height: modalHeight }}
        width={modalWidth}
      // bodyStyle={{ minHeight: '180px' }}
      />
    </div>
  );
});

Tag.displayName = 'Tag';

export default connect(Tag);
export type { IProps };
